/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2019年1月7日
 */

package com.massyframework.beanskin.spring.beancontext;

import java.util.Objects;

import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.io.DefaultResourceLoader;

import com.massyframework.beanskin.assembly.Assembly;
import com.massyframework.beanskin.spring.beancontext.util.ProfileUtils;



/**
 * {@link DependencyServiceInitializer}, 实现{@link ApplicationContextInitializer}接口，
 * 提供在ApplicationContext刷新前执行对ApplicationContext的配置
 */
public class DependencyServiceInitializer<C extends ConfigurableApplicationContext>
        implements ApplicationContextInitializer<C> {

    private final DependencyServiceBeanDefinitionRegistryPostProcessor processor;

    /**
     * 构造方法
     */
    public DependencyServiceInitializer(DependencyServiceBeanDefinitionRegistryPostProcessor processor) {
        this.processor = Objects.requireNonNull(processor, "\"processor\" cannot be null.");
    }

    /**
     * 初始化Spring ApplicationContext
     * @param c
     */
    @Override
    public void initialize(C c) {
    	Assembly assembly = this.processor.getAssociatedAssembly();
        this.setClassLoader(c, assembly);
        this.addBeanFactoryPostProcessor(c, this.processor);
        
        ConfigurableEnvironment env = c.getEnvironment();
        
        // 获取 PropertySource
        MutablePropertySources propertySources = env.getPropertySources();
        propertySources.addLast(new AssemblyPropertySource(assembly));

        ProfileUtils.setActiveProfile(assembly, c);
    }

    /**
     * 初始化类加载器
     * @param c {@link C}
     * @param assembly {@link Assembly}, 装配件
     */
    private void setClassLoader(C c, Assembly assembly){
        if (c instanceof DefaultResourceLoader){
            ((DefaultResourceLoader)c).setClassLoader(assembly.getModuleClassLoader());
        }
    }

    /**
     * 添加BeanFactoryPostProcessor
     * @param c {@link C}
     * @param processor {@link BeanFactoryPostProcessor}
     */
    protected void addBeanFactoryPostProcessor(C c, BeanFactoryPostProcessor processor){
        c.addBeanFactoryPostProcessor(processor);
    }


    /**
     * 依赖服务Bean定义注册处理器
     * @return {@link DependencyServiceBeanDefinitionRegistryPostProcessor}
     */
    public DependencyServiceBeanDefinitionRegistryPostProcessor getBeanFactoryPostProcessor(){
        return this.processor;
    }
}
